﻿using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sasa.QualityTools.CodeAnalysis.Core.Models;
using System.IO;

namespace Sasa.QualityTools.CodeAnalysis.Core.Tests.Unit.Models
{
    [TestFixture]
    public class MetricsReportTest
    {
        private static readonly string ResourceDir = Path.Combine(Environment.CurrentDirectory, "Resources", "Models", "MetricsReport");

        private MetricsReport testee;


        [SetUp]
        public void SetUp()
        {
            testee = new MetricsReport();
        }

        [TestCase(null)]
        [TestCase("")]
        [TestCase(".\\notexist.xml")]
        public void LoadShouldThrowExceptionWhenPathIsInvalid(string path)
        {
            Assert.Throws<InvalidOperationException>(() => testee.Load(path));
        }

        [Test]
        public void LoadShouldThrowExceptionWhenPassedPathOfBrokenXml()
        {
            var path = Path.Combine(ResourceDir, "BrokenXml.xml");
            Assert.Throws<CodeAnalysisException>(() => testee.Load(path));
        }

        [Test]
        public void LoadShouldBuildUpMemberMetricsCorrectly()
        {
            var path = Path.Combine(ResourceDir, "MemberMetrics.xml");

            testee.Load(path);

            Assert.AreEqual(2, testee.MetricValues.Count);

            var metrics = testee.MetricValues.ElementAt(0);
            Assert.AreEqual(CodeKind.Member, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.AreEqual("ABC.DEF", metrics.Namespace);
            Assert.AreEqual("XXX", metrics.TypeName);
            Assert.AreEqual("YYY() : void", metrics.Signature);
            Assert.AreEqual(100, metrics.MaintainabilityIndex);
            Assert.AreEqual(1, metrics.CyclomaticComplexity);
            Assert.AreEqual(2, metrics.ClassCoupling);
            Assert.AreEqual(3, metrics.LinesOfCode);
            Assert.IsFalse(metrics.DepthOfInheritance.HasValue);
            Assert.AreEqual("C:\\tmp\\XXX.cs", metrics.Path);
            Assert.AreEqual(1024, metrics.Line.Value);

            metrics = testee.MetricValues.ElementAt(1);
            Assert.AreEqual(CodeKind.Member, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.AreEqual("ABC.DEF", metrics.Namespace);
            Assert.AreEqual("XXX", metrics.TypeName);
            Assert.AreEqual("ZZZ() : void", metrics.Signature);
            Assert.AreEqual(50, metrics.MaintainabilityIndex);
            Assert.AreEqual(4, metrics.CyclomaticComplexity);
            Assert.AreEqual(5, metrics.ClassCoupling);
            Assert.AreEqual(6, metrics.LinesOfCode);
            Assert.IsFalse(metrics.DepthOfInheritance.HasValue);
            Assert.IsNull(metrics.Path);
            Assert.AreEqual(1, metrics.Line.Value);
        }

        [Test]
        public void LoadShouldFilterOutMetricValuesThatAreMatchedPatternWhenFilterIsSpecified()
        {
            var path = Path.Combine(ResourceDir, "MemberMetricsWithFilter.xml");

            testee.Filter = new CodeAnalysisResultValueFileNameFilter(new string[] { "foo" });
            testee.Load(path);

            Assert.AreEqual(2, testee.MetricValues.Count);

            var metrics = testee.MetricValues.ElementAt(0);
            Assert.AreEqual(CodeKind.Member, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.AreEqual("ABC.DEF", metrics.Namespace);
            Assert.AreEqual("XXX", metrics.TypeName);
            Assert.AreEqual("YYY() : void", metrics.Signature);
            Assert.AreEqual(100, metrics.MaintainabilityIndex);
            Assert.AreEqual(1, metrics.CyclomaticComplexity);
            Assert.AreEqual(2, metrics.ClassCoupling);
            Assert.AreEqual(3, metrics.LinesOfCode);
            Assert.IsFalse(metrics.DepthOfInheritance.HasValue);
            Assert.AreEqual("C:\\tmp\\bar.cs", metrics.Path);
            Assert.AreEqual(1024, metrics.Line.Value);

            metrics = testee.MetricValues.ElementAt(1);
            Assert.AreEqual(CodeKind.Member, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.AreEqual("ABC.DEF", metrics.Namespace);
            Assert.AreEqual("XXX", metrics.TypeName);
            Assert.AreEqual("ZZZ() : void", metrics.Signature);
            Assert.AreEqual(50, metrics.MaintainabilityIndex);
            Assert.AreEqual(4, metrics.CyclomaticComplexity);
            Assert.AreEqual(5, metrics.ClassCoupling);
            Assert.AreEqual(6, metrics.LinesOfCode);
            Assert.IsFalse(metrics.DepthOfInheritance.HasValue);
            Assert.IsNull(metrics.Path);
            Assert.AreEqual(1, metrics.Line.Value);
        }

        [Test]
        public void LoadShouldBuildUpTypeMetricsCorrectly()
        {
            var path = Path.Combine(ResourceDir, "TypeMetrics.xml");

            testee.Load(path);

            Assert.AreEqual(1, testee.MetricValues.Count);

            var metrics = testee.MetricValues.ElementAt(0);
            Assert.AreEqual(CodeKind.Type, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.AreEqual("ABC.DEF", metrics.Namespace);
            Assert.AreEqual("XXX", metrics.TypeName);
            Assert.IsNull(metrics.Signature);
            Assert.AreEqual(100, metrics.MaintainabilityIndex);
            Assert.AreEqual(1, metrics.CyclomaticComplexity);
            Assert.AreEqual(2, metrics.ClassCoupling);
            Assert.AreEqual(3, metrics.LinesOfCode);
            Assert.AreEqual(4, metrics.DepthOfInheritance.Value);
            Assert.IsNull(metrics.Path);
            Assert.IsFalse(metrics.Line.HasValue);
        }

        [Test]
        public void LoadShouldBuildUpNamespaceMetricsCorrectly()
        {
            var path = Path.Combine(ResourceDir, "NamespaceMetrics.xml");

            testee.Load(path);

            Assert.AreEqual(1, testee.MetricValues.Count);

            var metrics = testee.MetricValues.ElementAt(0);
            Assert.AreEqual(CodeKind.Namespace, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.AreEqual("ABC.DEF", metrics.Namespace);
            Assert.IsNull(metrics.TypeName);
            Assert.IsNull(metrics.Signature);
            Assert.AreEqual(100, metrics.MaintainabilityIndex);
            Assert.AreEqual(1, metrics.CyclomaticComplexity);
            Assert.AreEqual(2, metrics.ClassCoupling);
            Assert.AreEqual(3, metrics.LinesOfCode);
            Assert.AreEqual(4, metrics.DepthOfInheritance.Value);
            Assert.IsNull(metrics.Path);
            Assert.IsFalse(metrics.Line.HasValue);
        }

        [Test]
        public void LoadShouldBuildUpAssemblyMetricsCorrectly()
        {
            var path = Path.Combine(ResourceDir, "AssemblyMetrics.xml");

            testee.Load(path);

            Assert.AreEqual(1, testee.MetricValues.Count);

            var metrics = testee.MetricValues.ElementAt(0);
            Assert.AreEqual(CodeKind.Module, metrics.Kind);
            Assert.AreEqual("asm.dll", metrics.AssemblyPath);
            Assert.IsNull(metrics.Namespace);
            Assert.IsNull(metrics.TypeName);
            Assert.IsNull(metrics.Signature);
            Assert.AreEqual(100, metrics.MaintainabilityIndex);
            Assert.AreEqual(1, metrics.CyclomaticComplexity);
            Assert.AreEqual(2, metrics.ClassCoupling);
            Assert.AreEqual(3, metrics.LinesOfCode);
            Assert.AreEqual(4, metrics.DepthOfInheritance.Value);
            Assert.IsNull(metrics.Path);
            Assert.IsFalse(metrics.Line.HasValue);
        }
    }
}
